package me.zhenqu.redis;

/**
 * Created by IntelliJ IDEA.
 * User: yibing.tan
 * Date: 11-11-14
 * Time: 下午4:10
 * To change this template use File | Settings | File Templates.
 */

import me.zhenqu.redis.utils.JavaObjectSerializer;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.*;
import org.codehaus.jackson.map.deser.CustomDeserializerFactory;
import org.codehaus.jackson.map.deser.StdDeserializerProvider;
import org.codehaus.jackson.map.ser.CustomSerializerFactory;
import org.codehaus.jackson.map.type.TypeFactory;
import org.joda.time.DateTime;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;

public class JSONSerializer implements JavaObjectSerializer {
    public static final ObjectMapper JSON;

    static {
        JSON = new ObjectMapper();
        JSON.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        CustomSerializerFactory cf = new CustomSerializerFactory();
        JSON.setSerializerFactory(cf);

        cf.addSpecificMapping(DateTime.class, new JsonSerializer<DateTime>() {
            @Override
            public void serialize(DateTime dateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
                long millis = dateTime == null ? 0 : dateTime.getMillis();
                jsonGenerator.writeNumber(millis);
            }
        });

        CustomDeserializerFactory sf = new CustomDeserializerFactory();
        JSON.setDeserializerProvider(new StdDeserializerProvider(sf));
        sf.addSpecificMapping(DateTime.class, new JsonDeserializer<DateTime>() {
            @Override
            public DateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
                return new DateTime(jsonParser.getLongValue());
            }
        });
    }

    public JSONSerializer() {

    }

    @Override
    public <T> T readObject(ByteBuffer buffer, Class<T> t) {
        byte[] buf = new byte[buffer.limit()];
        buffer.get(buf);
        return readObject(buf, t);
    }

    @Override
    public <T> T readObject(byte[] buffer, Class<T> t) {
        try {
            return JSON.readValue(new String(buffer), t);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public ByteBuffer writeObject(int maxSize, Object o) {
        return ByteBuffer.wrap(writeObjectToArray(maxSize, o));
    }

    @Override
    public byte[] writeObjectToArray(int maxSize, Object o) {
        try {
            return JSON.writeValueAsBytes(o);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public <TT> Collection<TT> readObjectArray(byte[] buffer, Class<TT> t) {
        try {
            return JSON.readValue(buffer, 0, buffer.length, TypeFactory.collectionType(ArrayList.class, t));
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public Object readFullObject(byte[] buffer) {
        try {
            String str = new String(buffer, "utf-8");
            int e = str.indexOf('"', 9);
            Class<?> c = Class.forName(str.substring(9, e));
            return readObject(str.substring(e + 9, str.length() - 1).getBytes(), c);
        } catch (UnsupportedEncodingException ignored) {
            return null;
        } catch (ClassNotFoundException e) {
            return null;
        }
//        return ;
    }

    @Override
    public byte[] writeFullObject(int maxSize, Object o) {
        String str;
        try {
            str = JSON.writeValueAsString(o);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        StringBuilder b = new StringBuilder(str.length() + 100);
        b.append("{\"type\":\"").append(o.getClass().getName()).append("\",\"data\":").append(str).append("}");
        try {
            return b.toString().getBytes("utf-8");
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

}

